package com.grape.handler;

import com.grape.constants.Constants;
import com.grape.constants.OAuthConstant;
import com.grape.property.WebsocketProperty;
import com.grape.utils.SpringUtil;
import com.grape.utils.StringUtils;
import com.grape.model.UserContext;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.AttributeKey;
import org.slf4j.Logger;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.token.TokenStore;

import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static io.netty.handler.codec.http.HttpUtil.isKeepAlive;


@ChannelHandler.Sharable
public class UserAuthHandler extends SimpleChannelInboundHandler<FullHttpRequest> {

    private static final Logger logger = org.slf4j.LoggerFactory.getLogger(UserAuthHandler.class);

    public static final AttributeKey<UserContext> USER_CONTEXT_ATTRIBUTE_KEY = AttributeKey.valueOf(Constants.USER_CONTEXT_ATTRIBUTE_KEY);

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
        try {
            String uri = request.uri();
            logger.info("uri: {}", uri);
            String token = uri.substring(uri.lastIndexOf(Constants.DIAGONAL) + 1);
            if (StringUtils.isBlank(token)) {
                ctx.channel().writeAndFlush(new TextWebSocketFrame(
                        Instant.now().toEpochMilli() + ":" + "收到消息"));
                DefaultFullHttpResponse response = new DefaultFullHttpResponse(
                        HttpVersion.HTTP_1_1, HttpResponseStatus.UNAUTHORIZED);
                sendHttpResponse(ctx, request, response);
                return;
            }
            OAuth2AccessToken oAuth2AccessToken = SpringUtil.getBean(TokenStore.class).readAccessToken(token);
            Map<String, Object> additionalInformation = oAuth2AccessToken.getAdditionalInformation();
            String userId = additionalInformation.get(OAuthConstant.ID).toString();
            if (StringUtils.isBlank(userId)) {
                sendHttpResponse(ctx, request, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.UNAUTHORIZED));
                return;
            }
            UserContext userContext = new UserContext(userId, token);
            ctx.channel().attr(USER_CONTEXT_ATTRIBUTE_KEY).set(userContext);
            ctx.fireUserEventTriggered(userContext);
        } catch (Exception e) {
            logger.error("认证失败", e);
            sendHttpResponse(ctx, request, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.UNAUTHORIZED));
        }
        request.setUri(SpringUtil.getBean(WebsocketProperty.class).getPath());
        ctx.fireChannelRead(request.retain());
    }

    private static void sendHttpResponse(ChannelHandlerContext ctx,
                                         FullHttpRequest req, DefaultFullHttpResponse res) {
        if (res.status().code() != HttpResponseStatus.OK.code()) {
            ByteBuf buf = Unpooled.copiedBuffer(res.status().toString(), StandardCharsets.UTF_8);
            res.content().writeBytes(buf);
            buf.release();
        }
        ChannelFuture f = ctx.channel().writeAndFlush(res);
        if (!isKeepAlive(req) || res.status().code() != HttpResponseStatus.OK.code()) {
            f.addListener(ChannelFutureListener.CLOSE);
        }
    }
}
